﻿using AForge.Video.DirectShow;
using ArcFaceSharp.Image;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace FaceAlive
{
    public class MainViewModel : ViewModelBase
    {
        System.Threading.CancellationTokenSource _ClockCTS =
            new System.Threading.CancellationTokenSource();
        const string SDK_KEY = "DgLj9PVRtecZ74qBW3re8kdwtgNiFVWVoWVvkvpQwy5y";
        const string APPID = "dgEj3AypzN7G7XoivS3WjFR5RMX2GiBjaxCmPsZbeTz";
        VideoCaptureDevice rgbDevice;
        VideoCaptureDevice hjDevice;
        ArcFaceSharp.ArcFaceCore rgbFace;
        ArcFaceSharp.ArcFaceCore hjFace;
        Bitmap currentHjImage;

        public MainViewModel()
        {
            Application.Current.Exit += Current_Exit;
            Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;
            Task.Run(() =>
            {
                while (!_ClockCTS.IsCancellationRequested)
                {
                    WindowTitle = $"硬件活体监测:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}";
                    Task.Delay(1000).Wait();
                }
            }, _ClockCTS.Token);
            
        }

        private void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
           
        }

        private void Current_Exit(object sender, ExitEventArgs e)
        {
            hjDevice?.Stop();
            rgbDevice?.Stop();
            _ClockCTS.Cancel();

        }

        private string _WindowTitle;
        public string WindowTitle
        {
            get { return _WindowTitle; }
            set { _WindowTitle = value; RaisePropertyChanged("WindowTitle"); }
        }

        private ImageSource _RgbVideo;

        public ImageSource RgbVideo
        {
            get { return _RgbVideo; }
            set { _RgbVideo = value; RaisePropertyChanged("RgbVideo"); }
        }

        private ImageSource _HJVideo;

        public ImageSource HJVideo
        {
            get { return _HJVideo; }
            set { _HJVideo = value; RaisePropertyChanged("HJVideo"); }
        }

        private string _DetectionResult = "等待检测";

        public string DetectionResult
        {
            get { return _DetectionResult; }
            set { _DetectionResult = value; RaisePropertyChanged("DetectionResult"); }
        }

        private string _WarmingBg = "SeaGreen";

        public string WarmingBg
        {
            get { return _WarmingBg; }
            set { _WarmingBg = value; RaisePropertyChanged("WarmingBg"); }
        }


        public RelayCommand InitVideo => new RelayCommand(() =>
        {
            rgbFace = new ArcFaceSharp.ArcFaceCore(APPID, SDK_KEY
                , ArcFaceSharp.ArcFace.ArcFaceDetectMode.IMAGE,
                 ArcFaceSharp.ArcFace.ArcFaceFunction.FACE_DETECT |
                 ArcFaceSharp.ArcFace.ArcFaceFunction.FACE_RECOGNITION,
                  ArcFaceSharp.ArcFace.DetectionOrientPriority.ASF_OP_0_ONLY, 10, 10);
            hjFace = new ArcFaceSharp.ArcFaceCore(APPID, SDK_KEY
                , ArcFaceSharp.ArcFace.ArcFaceDetectMode.IMAGE,
                 ArcFaceSharp.ArcFace.ArcFaceFunction.FACE_DETECT |
                 ArcFaceSharp.ArcFace.ArcFaceFunction.FACE_RECOGNITION,
                  ArcFaceSharp.ArcFace.DetectionOrientPriority.ASF_OP_0_ONLY, 10, 10);


            rgbDevice = new VideoCaptureDevice();
            var filter = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            rgbDevice.Source = filter[2].MonikerString;
            rgbDevice.VideoResolution = rgbDevice.VideoCapabilities.FirstOrDefault(ss => ss.FrameSize == new System.Drawing.Size(640, 480));
            rgbDevice.NewFrame += RgbDevice_NewFrame;
            hjDevice = new VideoCaptureDevice();
            hjDevice.Source = filter[1].MonikerString;
            hjDevice.VideoResolution = hjDevice.VideoCapabilities.FirstOrDefault(ss => ss.FrameSize == new System.Drawing.Size(640, 480));
            hjDevice.NewFrame += HjDevice_NewFrame;
            hjDevice.Start();
            rgbDevice.Start();
        });

        private void HjDevice_NewFrame(object sender, AForge.Video.NewFrameEventArgs eventArgs)
        {
            currentHjImage = AForge.Imaging.Image.Clone(eventArgs.Frame);
            //var bitmap = eventArgs.Frame;
            //if (bitmap != null)
            //{
            //    using (var imageData = ImageDataConverter.ConvertToImageData(bitmap))
            //    {
            //        var detectionResult =
            //        hjFace.FaceDetection(imageData);
            //        if (detectionResult.MultiFaceInfo.faceNum > 0)
            //        {
            //            var first = detectionResult.FaceInfoList.FirstOrDefault();
            //            var firstRect = first.faceRect.Rectangle;
            //            Console.WriteLine($"HJ ->TOP:{first.faceRect.top}LEFT:{first.faceRect.left}");
            //            //用RGB的人脸位置截取红外的图像

            //            using (var g = Graphics.FromImage(bitmap))
            //            {
            //                g.DrawRectangle(Pens.Green, firstRect);
            //            }
            //        }
            //        HJVideo = ToImageSource(bitmap);
            //    }

            //}

        }

        private void RgbDevice_NewFrame(object sender, AForge.Video.NewFrameEventArgs eventArgs)
        {

            var bitmap = eventArgs.Frame;
            if (bitmap != null)
            {
                try
                {
                    using (var imageData = ImageDataConverter.ConvertToImageData(bitmap))
                    {
                        var detectionResult =
                        rgbFace.FaceDetection(imageData);
                        if (detectionResult.MultiFaceInfo.faceNum > 0)
                        {
                            var first = detectionResult.FaceInfoList.FirstOrDefault();
                            var firstRect = first.faceRect.Rectangle;
                            Console.WriteLine($"RGB->TOP:{first.faceRect.top}LEFT:{first.faceRect.left}");
                            //用RGB的人脸位置截取红外的图像
                            Bitmap hjFaceImage = null;
                            if (currentHjImage != null)
                            {
                                var showImage = GetImagePart(currentHjImage, firstRect);
                                hjFaceImage = AForge.Imaging.Image.Clone(showImage);
                                HJVideo = ToImageSource(showImage);
                            }

                            using (var g = Graphics.FromImage(bitmap))
                            {
                                g.DrawRectangle(Pens.Green, firstRect);
                            }

                            #region 提取红外图像人脸
                            if (hjFaceImage != null)
                            { 
                                using (var hjimageData = ImageDataConverter.ConvertToImageData(hjFaceImage))
                                {
                                    var hjdetectionResult =
                                        hjFace.FaceDetection(hjimageData);
                                    if (hjdetectionResult.MultiFaceInfo.faceNum > 0)
                                    {
                                        DetectionResult = "当前目标为活体";
                                        WarmingBg = "SeaGreen";
                                    }
                                    else
                                    {
                                        DetectionResult = "当前目标为非活体";
                                        WarmingBg = "Red";
                                    }
                                }
                                hjFaceImage.Dispose();
                            }
                            #endregion

                        }
                        RgbVideo = ToImageSource(bitmap);
                    }
                }
                catch 
                {

                }
            }

        }

        private Bitmap GetImagePart(Bitmap from, Rectangle rectangle)
        {
            Bitmap bitmap = new Bitmap(rectangle.Width, rectangle.Height);
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.DrawImage(from, 0, 0, rectangle, GraphicsUnit.Pixel);
            }
            return bitmap;
        }

        private BitmapImage ToImageSource(Bitmap bitmap)
        {
            MemoryStream ms = new MemoryStream();
            bitmap.Save(ms, ImageFormat.Bmp);
            var imageSource = new BitmapImage();
            imageSource.BeginInit();
            imageSource.StreamSource = ms;
            imageSource.EndInit();
            if (imageSource.CanFreeze) imageSource.Freeze();
            return imageSource;
        }
    }
}
